package 多线程;

import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
import java.util.concurrent.FutureTask;
import java.util.concurrent.RunnableFuture;

/*
Java语言内置了多线程支持。当Java程序启动的时候，实际上是启动了一个JVM进程，然后，JVM启动主线程来执行main()方法。
在main()方法中，我们又可以启动其他线程。

要创建一个新线程非常容易，我们需要实例化一个Thread实例，然后调用它的start()方法：

// 多线程
public class Main {
    public static void main(String[] args) {
        Thread t = new Thread();
        t.start(); // 启动新线程
    }
}


但是这个线程启动后实际上什么也不做就立刻结束了。我们希望新线程能执行指定的代码，有以下几种方法：

-通过实现 Runnable 接口；
-通过继承 Thread 类本身；
-通过 Callable 和 Future 创建线程
方法一：从Thread派生一个自定义类，然后覆写run()方法：
*/
// 多线程
/*public class 创建新线程 {
    public static void main(String[] args) {
        Thread t = new MyThread();
        t.start(); // 启动新线程  即调用t的run()方法
    }
}

class MyThread extends Thread {
    @Override
    public void run() {
        System.out.println("start new thread!");
    }
}*/
/*
start new thread!
执行上述代码，注意到start()方法会在内部自动调用实例的run()方法。

方法二：创建Thread实例时，传入一个Runnable实例：

public class Thread implements Runnable {
	...
}

@FunctionalInterface
public interface Runnable {
    void run();
}*/
// 多线程
/*public class 创建新线程 {
    public static void main(String[] args) {
        Thread t = new Thread(new MyRunnable());// 调用构造函数new Thread(Runnable task)
        t.start(); // 启动新线程
    }
}

class MyRunnable implements Runnable {
    @Override
    public void run() {
        System.out.println("start new thread!");
    }
}*/

//亦可：
/*class MyRunnable implements Runnable {
	Thread t;
	String threadName;

	public MyRunnable(String threadName) {
		this.threadName=threadName;
	}

    @Override
    public void run() {
        System.out.println("start "+threadName+"!");
    }

    public void start() {
    	Thread t=new Thread(this,threadName);//调用构造函数new Thread(Runnable task, String name)
    	t.start();//此start()为线程Thread实例的start(),非MyRunnable实例的start()
    }
}
public class 创建新线程 {
    public static void main(String[] args) {
        MyRunnable R = new MyRunnable("thread-1");
        R.start(); // 启动新线程
    }
}*/
/*
public class 创建新线程 {
    public static void main(String[] args) {
        Thread t = new Thread(new MyRunnable()){
          public String toString(){
              return "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa";}
         };
         System.out.println(t);
         t.start(); // 启动新线程
    }
}

class MyRunnable extends Thread {
//class MyRunnable implements Runnable {
    @Override
    public void run() {
        System.out.println("start new thread!");
    }
}
*/

//start new thread!
//或者用Java8引入的lambda语法进一步简写为：
//
//// 多线程
/*public class 创建新线程 {
    public static void main(String[] args) {
        Thread t = new Thread(() -> {
            System.out.println("start new thread!");
        });
        //Thread t = new Thread(() -> System.out.println("start new thread!"));//单条语句进一步简化
        t.start(); // 启动新线程
    }
}*/

//有童鞋会问，使用线程执行的打印语句，和直接在main()方法执行有区别吗？
//
//区别大了去了。我们看以下代码：
//
/*public class 创建新线程 {
    public static void main(String[] args) {
        System.out.println("main start...");
        Thread t = new Thread() {
            public void run() {
                System.out.println("thread run...");
                System.out.println("thread end.");
            }
        };
        t.start();
        System.out.println("main end...");
    }
}*/
//我们用蓝色表示主线程，也就是main线程，main线程执行的代码有4行，首先打印main start，然后创建Thread对象，紧接着调
//用start()启动新线程。当start()方法被调用时，JVM就创建了一个新线程，我们通过实例变量t来表示这个新线程对象，并开始执行。
//
//接着，main线程继续执行打印main end语句，而t线程在main线程执行的同时会并发执行，打印thread run和thread end语句。
//
//当run()方法结束时，新线程就结束了。而main()方法结束时，主线程也结束了。
//
//我们再来看线程的执行顺序：
//
//main线程肯定是先打印main start，再打印main end；
//t线程肯定是先打印thread run，再打印thread end。
//但是，除了可以肯定，main start会先打印外，main end打印在thread run之前、thread end之后或者之间，都无法确定。
//因为从t线程开始运行以后，两个线程就开始同时运行了，并且由操作系统调度，程序本身无法确定线程的调度顺序。
//
//要模拟并发执行的效果，我们可以在线程中调用Thread.sleep()，强迫当前线程暂停一段时间：
//
//// 多线程
/*public class 创建新线程 {
    public static void main(String[] args) {
        System.out.println("main start...");
        Thread t = new Thread() {
            public void run() {
                System.out.println("thread run...");
                try {
                    Thread.sleep(10);
                } catch (InterruptedException e) {}
                System.out.println("thread end.");
            }
        };
        t.start();
        try {
            Thread.sleep(20);
        } catch (InterruptedException e) {}
        System.out.println("main end...");
    }
}*/
//
//sleep()传入的参数是毫秒。调整暂停时间的大小，我们可以看到main线程和t线程执行的先后顺序。
//
//要特别注意：直接调用Thread实例的run()方法是无效的：
//
/*public class 创建新线程 {
    public static void main(String[] args) {
        Thread t = new MyThread();
        t.run();
        t.start();
    }
}

class MyThread extends Thread {
    public void run() {
        System.out.println("hello");
    }
}*/
/*
直接调用run()方法，相当于调用了一个普通的Java方法，当前线程并没有任何改变，也不会启动新线程。上述代码实际上是在main()方法内部
又调用了run()方法，打印hello语句是在main线程中执行的，没有任何新线程被创建。

必须调用Thread实例的start()方法才能启动新线程，如果我们查看Thread类的源代码，会看到start()方法内部调用了
一个private native void start0()方法，native修饰符表示这个方法是由JVM虚拟机内部的C代码实现的，不是由Java代码实现的。

线程的优先级
可以对线程设定优先级，设定优先级的方法是：
Thread.setPriority(int n) // 1~10, 默认值5
优先级高的线程被操作系统调度的优先级较高，操作系统对高优先级线程可能调度更频繁，但我们决不能通过设置优先级来确保高优先级的线程一定会先执行。

一个线程对象只能调用一次start()方法；
线程的执行代码写在run()方法中；
线程调度由操作系统决定，程序本身无法决定调度顺序；
Thread.sleep()可以把当前线程暂停一段时间。

《创建一个线程》
Java 提供了三种创建线程的方法：

1.通过实现 Runnable 接口；
2.通过继承 Thread 类本身；
3.通过 Callable 和 Future 创建线程。

1.通过实现 Runnable 接口来创建线程
创建一个线程，最简单的方法是创建一个实现 Runnable 接口的类。
为了实现 Runnable，一个类只需要执行一个方法调用 run()，声明如下：
public void run()

你可以重写该方法，重要的是理解的 run() 可以调用其他方法，使用其他类，并声明变量，就像主线程一样。

在创建一个实现 Runnable 接口的类之后，你可以在类中实例化一个线程对象。

Thread 定义了几个构造方法，下面的这个是我们经常使用的：
Thread(Runnable threadOb,String threadName);
这里，threadOb 是一个实现 Runnable 接口的类的实例，并且 threadName 指定新线程的名字。

新线程创建之后，你调用它的 start() 方法它才会运行。

void start();
下面是一个创建线程并开始让它执行的实例：
*/
/*class RunnableDemo implements Runnable {
   private Thread t;
   private String threadName;
   
   RunnableDemo(String name) {
      threadName = name;
      System.out.println("Creating " +  threadName );
   }
   
   public void run() {
      System.out.println("Running " +  threadName );
      try {
    	  for(int i = 4; i > 0; i--) {
            System.out.println("Thread: " + threadName + ", " + i);
            // 让线程睡眠一会
            Thread.sleep(10);
         }
      }catch (InterruptedException e) {
         System.out.println("Thread " +  threadName + " interrupted.");
      }
      System.out.println("Thread " +  threadName + " exiting.");
   }
   
   public void start() {//此start()为RunnableDemo实例的方法
      System.out.println("Starting " +  threadName );
      if (t == null) {
         t = new Thread (this, threadName);
         t.start();//此start()为Thread实例的方法
      }
   }
}
 
public class 创建新线程 {
 
   public static void main(String args[]) {
      RunnableDemo R1 = new RunnableDemo( "Thread-1");
      R1.start();
      
      RunnableDemo R2 = new RunnableDemo( "Thread-2");
      R2.start();
      
   }   
}*/
/*
编译以上程序运行结果如下：

Creating Thread-1
Starting Thread-1
Creating Thread-2
Starting Thread-2
Running Thread-1
Thread: Thread-1, 4
Running Thread-2
Thread: Thread-2, 4
Thread: Thread-1, 3
Thread: Thread-2, 3
Thread: Thread-1, 2
Thread: Thread-2, 2
Thread: Thread-1, 1
Thread: Thread-2, 1
Thread Thread-1 exiting.
Thread Thread-2 exiting.

2.通过继承Thread来创建线程
创建一个线程的第二种方法是创建一个新的类，该类继承 Thread 类，然后创建一个该类的实例。

继承类必须重写 run() 方法，该方法是新线程的入口点。它也必须调用 start() 方法才能执行。

该方法尽管被列为一种多线程实现方式，但是本质上也是实现了 Runnable 接口的一个实例。（public class Thread implements Runnable）

实例
*/
/*class ThreadDemo extends Thread {
   private Thread t;
   private String threadName;
   
   ThreadDemo(String name) {
      threadName = name;
      System.out.println("Creating " +  threadName );
   }

   @Override
   public void run() {
      System.out.println("Running " +  threadName );
      try {
         for(int i = 4; i > 0; i--) {
            System.out.println("Thread: " + threadName + ", " + i);
            // 让线程睡眠一会
            Thread.sleep(50);
         }
      }catch (InterruptedException e) {
         System.out.println("Thread " +  threadName + " interrupted.");
      }
      System.out.println("Thread " +  threadName + " exiting.");
   }
   
   public void start() {
      System.out.println("Starting " +  threadName );
      if (t == null) {
         t = new Thread (this, threadName);
         t.start ();//void java.lang.Thread.start()
      }
   }
}
 
//public class TestThread {
public class 创建新线程 {
 
   public static void main(String args[]) {
      ThreadDemo T1 = new ThreadDemo( "Thread-1");
      T1.start();//void 多线程.ThreadDemo.start()
      
      ThreadDemo T2 = new ThreadDemo( "Thread-2");
      T2.start();//void 多线程.ThreadDemo.start()
   }   
}*/
//
//编译以上程序运行结果如下：
//
//Creating Thread-1
//Starting Thread-1
//Creating Thread-2
//Starting Thread-2
//Running Thread-1
//Thread: Thread-1, 4
//Running Thread-2
//Thread: Thread-2, 4
//Thread: Thread-1, 3
//Thread: Thread-2, 3
//Thread: Thread-1, 2
//Thread: Thread-2, 2
//Thread: Thread-1, 1
//Thread: Thread-2, 1
//Thread Thread-1 exiting.
//Thread Thread-2 exiting.
/*
Thread 方法
下表列出了Thread类的一些重要方法：

序号	                            方法描述
1     public void start()  使该线程开始执行；Java 虚拟机调用该线程的 run 方法。
2     public void run()    如果该线程是使用独立的 Runnable 运行对象构造的，则调用该 Runnable 对象的 run 方法；否则，该
                           方法不执行任何操作并返回。
3     public final void setName(String name)   改变线程名称，使之与参数 name 相同。
4     public final void setPriority(int priority)   更改线程的优先级。
5     public final void setDaemon(boolean on)   将该线程标记为守护线程或用户线程。
6     public final void join(long millisec)  等待该线程终止的时间最长为 millis 毫秒。
7     public void interrupt()  中断线程。
8     public final boolean isAlive()  测试线程是否处于活动状态。

上述方法是被 Thread 对象调用的，下面表格的方法是 Thread 类的静态方法。

序号                                                方法描述
1 public static void yield()                 暂停当前正在执行的线程对象，并执行其他线程。 也有可能继续执行？
2 public static void sleep(long millisec)    在指定的毫秒数内让当前正在执行的线程休眠（暂停执行），此操作受到系统计时器和调度程序精度和准确性的影响。
3 public static boolean holdsLock(Object x)  当且仅当当前线程在指定的对象上保持监视器锁时，才返回 true。
4 public static Thread currentThread()       返回对当前正在执行的线程对象的引用。
5 public static void dumpStack()             将当前线程的堆栈跟踪打印至标准错误流。
实例
如下的ThreadClassDemo 程序演示了Thread类的一些方法：
 */
/*
//展示了join()、deamon()的使用
class DisplayMessage implements Runnable {
   private String message;
   
   public DisplayMessage(String message) {
      this.message = message;
   }
   
   @Override
   public void run() {
	   System.out.println(message);
      while(true) {
         //System.out.println(message);
      }
   }
}

class GuessANumber extends Thread {
   private int number;
   public GuessANumber(int number) {
      this.number = number;
   }
   
   public void run() {
      int counter = 0;
      int guess = 0;
      do {
         guess = (int) (Math.random() * 100 + 1);
         System.out.println(this.getName() + " guesses " + guess);
         //System.out.println(Thread.currentThread().getName() + " guesses " + guess);
         counter++;
      } while(guess != number);
      System.out.println("** Correct! " + this.getName() + " in " + counter + " guesses.**");
   }
}

public class 创建新线程 {
 
   public static void main(String [] args) {
      Runnable hello = new DisplayMessage("thread1 Hello");
      Thread thread1 = new Thread(hello);
      //thread1.setName("thread1 hello");
      thread1.setDaemon(true);//thread1线程无限循环，一旦其他线程执行完毕，立即结束该线程运行
      System.out.println("Starting hello thread..."+thread1.isDaemon());
      thread1.start();
      
      Runnable bye = new DisplayMessage("Goodbye");
      Thread thread2 = new Thread(bye);
      thread2.setPriority(Thread.MIN_PRIORITY);
      thread2.setDaemon(true);
      System.out.println("Starting goodbye thread..."+thread1.isDaemon()+thread2.isDaemon());
      thread2.start();
 
      System.out.println("Starting thread3...");
      Thread thread3 = new GuessANumber(27);
      thread3.setName("thread3-");
      thread3.start();
      try {
         thread3.join();//main线程等待thread3线程结束后再执行，也即thread4线程等待thread3线程结束再执行
      }catch(InterruptedException e) {
         System.out.println("Thread interrupted.");
      }
      System.out.println("Starting thread4...");
      Thread thread4 = new GuessANumber(75);
      thread4.setName("thread4-");
      thread4.start();
      try {
         thread4.join();//main线程等待thread3线程结束后再执行，也即thread4线程等待thread3线程结束再执行
      }catch(InterruptedException e) {
         System.out.println("Thread interrupted.");
      }
      System.out.println("main() is ending...");
   }
}
*/
//
//运行结果如下，每一次运行的结果都不一样。
//
//Starting hello thread...
//Starting goodbye thread...
//Hello
//Hello
//Hello
//Hello
//Hello
//Hello
//Goodbye
//Goodbye
//Goodbye
//Goodbye
//Goodbye
//.......
/*
3.通过 Callable 和 Future 创建线程
·创建 Callable 接口的实现类，并实现 call() 方法，该 call() 方法将作为线程执行体，并且有返回值。
·创建 Callable 实现类的实例，使用 FutureTask 类来包装 Callable 对象，该 FutureTask 对象封装了该 Callable 对象的 call() 方法的返回值。
·使用 FutureTask 对象作为 Thread 对象的 target 创建并启动新线程。
·调用 FutureTask 对象的 get() 方法来获得子线程执行结束后的返回值。

实例
*/
/*import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;
public class 创建新线程 implements Callable<Integer> {
	public static void main(String[] args) {
		创建新线程 ctt = new 创建新线程();
		FutureTask<Integer> ft = new FutureTask<Integer>(ctt);
		for (int i = 0; i < 100; i++) {
			System.out.println(Thread.currentThread().getName() + " 的循环变量i的值" + i);
			if (i == 20) {
				new Thread(ft, "有返回值的线程在运行").start();
//			System.out.println(i);
			}
		}
		try {
			System.out.println("子线程的返回值：" + ft.get());
		} catch (InterruptedException e) {
			e.printStackTrace();
		} catch (ExecutionException e) {
			e.printStackTrace();
		}

	}

	@Override
	public Integer call() throws Exception {
		int i = 0;
		for (; i < 100; i++) {
			Thread.sleep(0);
			System.out.println(Thread.currentThread().getName() + " " + i);
		}
		return i;
	}
}*/
//重写 call 方法，这种方式可以通过 FutureTask 获取任务执行的返回值
public class 创建新线程 implements Callable<String> {
   public String call() throws Exception {
       return "Hello,i am running!";
   }

   public static void main(String[] args) {
       //创建异步任务
   	//FutureTask实现了Future接口的一个具体类，同时也实现了Runnable接口。
       FutureTask<String> task=new FutureTask<String>(new 创建新线程());//FutureTask<V>(Callable<V> callable)，等同：Runnable task
       //FutureTask<V>继承自Runnable接口
       //public class FutureTask<V> implements RunnableFuture<V>
       //构造函数：public FutureTask(Callable<V> callable) {
       //public interface RunnableFuture<V> extends Runnable, Future<V> {
       //   void run();
       //}
       //启动线程
       new Thread(task).start();
       try {
           //等待执行完成，并获取返回结果
           String result=task.get();
           System.out.println(result);
       } catch (InterruptedException e) {
           e.printStackTrace();
       } catch (ExecutionException e) {
           e.printStackTrace();
       }
   }
}

/*
创建线程的三种方式的对比：
·采用实现 Runnable、Callable 接口的方式创建多线程时，线程类只是实现了 Runnable 接口或 Callable 接口，还可以继承其他类。
·使用继承 Thread 类的方式创建多线程时，编写简单，如果需要访问当前线程，则无需使用 Thread.currentThread() 方法，直接使用 this 即可获得当前线程。

1.Runnable接口是java1.1就有的，Callable接口是java1.5才有的，可以认为Callable接口是升级版的Runnable接口；
2.Runnable接口里线程任务是在run方法里写的，Callable接口里线程任务是在call方法里写；
3.Callable接口的任务执行后会有返回值，Runnable接口的任务无返回值（void）；
4.call方法支持抛出异常，run方法不可以；
5.加入线程池运行，Runnable使用ExecutorService的execute方法，Callable使用ExecutorService的submit方法；
6.运行Callable任务可以拿到一个Future对象，表示异步计算的结果。Future对象封装了检查计算是否完成、检索计算的结果的方法，而Runnable接口没有。

  第5点提到了Callable使用ExecutorService的submit方法，这里看一下ExecutorService接口里的submit方法的重载情况：

·<T> Future<T> submit(Callable<T> task);
·<T> Future<T> submit(Runnable task, T result);
·Future<?> submit(Runnable task);
常用的是第一个和第三个，这两个方法分别提交实现了Callable接口的类和实现了Runnable接口的类作为线程任务，返回异步计算结果Future，Future里面封装了一些实用方法可
以对异步计算结果进行进一步处理。


线程的几个主要概念
在多线程编程时，你需要了解以下几个概念：

线程同步
线程间通信
线程死锁
线程控制：挂起、停止和恢复
多线程的使用
有效利用多线程的关键是理解程序是并发执行而不是串行执行的。例如：程序中有两个子系统需要并发执行，这时候就需要利用多线程编程。

通过对多线程的使用，可以编写出非常高效的程序。不过请注意，如果你创建太多的线程，程序执行的效率实际上是降低了，而不是提升了。

请记住，上下文的切换开销也很重要，如果你创建了太多的线程，CPU 花费在上下文的切换的时间将多于执行程序的时间
*/
//《线程的创建与使用》
//1、 通过继承Thread
//在创建一个分线程的时候，我们可直接继承Thread类，通过该类实例化的对象进行开启线程。具体步骤如下：
//
//创建一个继承于 Thread类 的子类
//重写 Thread类 中的 run()，将此线程执行的操作声明在 run() 中
//创建 Thread类 的子类的对象
//通过此对象调用 start()
//1. 创建一个继承于Thread类的子类
//public class 创建新线程 extends Thread{
//    //这里的main属于主线程，而建立的 创建新线程 对象属于分支线程在多线程里面，只有调用了start()方法，两个线程会同时执行
//    public static void main(String[] args) {
//        //3. 创建Thread类的子类的对象
//    	创建新线程 t1 = new 创建新线程();
//    	创建新线程 t2 = new 创建新线程();
//        //4. 通过对象调用start()方法
//        t1.start();
//        t2.start();
//        //在主线程中添加输出语句进行验证两个线程是否同时执行
//        for (int i = 0; i < 10; i++) {
//            System.out.println(Thread.currentThread().getName() + ":" + i);     //输出线程名，检测各线程的执行
//        }
//    }
//
//    //2. 重写Thread类中的run()方法
//    @Override
//    public void run() {
//        for (int i = 0; i < 50; i++) {
//            if(i%2 == 0) {
//                System.out.println(Thread.currentThread().getName() + ":" + i); //输出线程名，检测各线程的执行
//            }
//        }
//    }
//}

//但在创建和使用线程的过程中需要注意下面两点：
//
//不能通过直接调用 run()方法 启动线程，这不是多线程，只是调用了方法而已
//若想再启动一个线程，不可用已经调用了 start() 的线程去执行，需重新创建一个线程的对象才行，否则会报IllegalThreadStateException
//由于有些线程只使用一次，因此我们可以通过匿名子类的方式对线程的核心内容进行编写，下面通过练习进行演示（创建两个线程，一个线程输出奇数，一个线程输出偶数）
//
//public class 创建新线程 {
//    //可按部就班根据步骤书写两个线程类继承Thread类，也可利用匿名子类
//    public static void main(String[] args) {
//        new Thread() {
//            @Override
//            public void run() {
//                for (int i = 0; i < 50; i++) {
//                    if(i % 2 == 0) {
//                        System.out.println(Thread.currentThread().getName() + ":" + i);
//                    }
//                }
//            }
//        }.start();
//        new Thread() {
//            @Override
//            public void run() {
//                for (int i = 0; i < 50; i++) {
//                    if(i % 2 != 0) {
//                        System.out.println(Thread.currentThread().getName() + ":" + i);
//                    }
//                }
//            }
//        }.start();
//    }
//}
//
//2、 通过实现Runnable接口
//Java 中的 lang包 下内置了 Runnable 接口，我们可通过实现 Runnable 接口中的 run() 方法进行创建线程。具体步骤如下：
//
//创建一个实现了 Runnable 接口的类
//实现类去实现 Runnable 中的抽象方法：run()
//创建实现类的对象
//将此对象作为参数传递到 Thread 类中的构造器中，创建 Thread 类中的对象
//通过 Thread 类中的对象调用 start()，其中调用了 Runnable 类型的 target 对象
////1. 创建一个实现了 Runnable 接口的类
/*public class 创建新线程 implements Runnable{
    public static void main(String[] args) {
        //3. 创建实现类的对象
    	创建新线程 threadRunnable = new 创建新线程();
        //4. 将此对象作为参数传递到 Thread 类中的构造器中，创建 Thread 类中的对象
        Thread t1 = new Thread(threadRunnable);
        Thread t2 = new Thread(threadRunnable);     //方式二中可通过 new 一个新的 Thread 对象开启新线程，共用一个实现类

        t1.setName("线程1");
        t2.setName("线程2");

        //5. 通过 Thread 类中的对象调用 start()
        t1.start();
        t2.start();
        for (int i = 0; i < 50; i++) {
            if(i % 2 != 0) {
                System.out.println(Thread.currentThread().getName() + ": " + i);
            }
        }
    }

    //2. 实现类去实现 Runnable 中的抽象方法：run()
    @Override
    public void run() {
        for (int i = 0; i < 50; i++) {
            if(i % 2 == 0) {
                System.out.println(Thread.currentThread().getName() + ": " + i);
            }
        }
    }
}*/
//
//3、 继承大战实现
//细心的伙伴可能已经发现，Thread类 其实也实现了 Runnable 接口，Thread类 也是 Runnable 接口的一个特殊的实现类。无论我们选择继
//承 Thread类 还是实现 Runnable接口 的方式进行创建线程，我们都需要重写 run()，将线程要执行的逻辑声明在 run() 中，都需要通
//过 start() 方法进行开启线程。那么这两种我们到底选择那种呢？
//
//开发中，优先选择实现 Runnable接口 的方式，原因如下并通过多个窗口卖票的案例进行展示：
//
//实现的方式没有类的单继承性的局限性
//实现的方式更适合来处理多个线程有共享数据的情况
///*=============方式一：继承 Thread类=================*/
/*public class 创建新线程 {
    public static void main(String[] args) {
        //创建三个窗口卖票线程
        Window w1 = new Window();
        Window w2 = new Window();
        Window w3 = new Window();
        //设置三个线程名
        w1.setName("窗口1");
        w2.setName("窗口2");
        w3.setName("窗口3");
        //开启三个线程
        w1.start();
        w2.start();
        w3.start();
    }
}
//创建继承了Thread类的子类
class Window extends Thread {
    private static int ticket = 100;        //设置为静态变量使得定义的多个变量公用共用同一个ticket变量
    @Override
    public void run() {
        while(ticket > 0) {
            System.out.println(Thread.currentThread().getName() + ": 当前票号为: " + ticket--);
        }
    }
}*/
//
///*=============方式二：实现 Runnable接口=================*/
/*public class 创建新线程{
    public static void main(String[] args) {
        //实例化实现类对象
        NewWindow newWindow = new NewWindow();
        //实例化三个窗口的线程
        Thread w1 = new Thread(newWindow,"窗口1");
        Thread w2 = new Thread(newWindow,"窗口2");
        Thread w3 = new Thread(newWindow,"窗口3");
        //重命名三个线程
//        w1.setName("窗口1");
//        w2.setName("窗口2");
//        w3.setName("窗口3");
        //启动三个线程
        w1.start();
        w2.start();
        w3.start();
    }
}

//实现 Runnable 接口
class NewWindow implements Runnable {
    private int ticket = 100;       //由于三个线程共用一个实现类，因此不需要使用static

    @Override
    public void run() {
        while(ticket > 0) {
            System.out.println(Thread.currentThread().getName() + ": 当前票号为: " + ticket--);
        }
    }
}*/
//
//四、线程中的常用方法
//run(): 通常需要重写Thread类中的此方法，将创建的线程要执行的操作声明在此方法中;
//
//@Override
//    public void run() {
//        for (int i = 0; i < 50; i++) {
//            if(i%2 == 0) {
//                System.out.println(i); 
//            }
//        }
//    }
//
//start(): 启动当前线程；调用当前线程的run();
//
//MyThread t1 = new MyThread();
//t1.start();
//
//currentThread(): 静态方法，返回执行当前代码的线程;
//
//getName(): 获得当前线程的名字;
//
//setName(): 设置当前线程的名字;
//
//System.out.println(Thread.currentThread().getName());
//Thread.currentThread.setName("线程1");
//
//yield(): 释放当前CPU的执行权，即线程遇到这一方法时会暂时将执行权转给其余线程;
//
//if(i % 20 == 0) {
//    yield();
//}
//
//join(): 会抛异常。在线程a中调用线程b的join()，此时线程a就会进入阻塞状态，直到线程b完全执行完之后，线程a才结束阻塞状态;
//
/*public class 创建新线程 {
    public static void main(String[] args) {
        MyThread t1 = new MyThread();
        t1.start();
        System.out.println("Hello");
        try {
        	System.out.println(Thread.currentThread().getName());
            t1.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("World");
    }
}
class MyThread extends Thread{
    @Override
    public void run() {
        for (int i = 0; i < 100; i++) {
            if(i % 2 == 0) {
                System.out.println(Thread.currentThread().getName() + ":" + i);
            }
        }
    }
}*/
//
//stop(): 已过时。当执行此方法时，强制结束当前线程;
//
//sleep(long millis): 会抛异常。让当前下线程**“睡眠”指定的 millis 毫秒**。在指定的 millis 毫秒。在指定的 millis 毫秒时间内，
//当前线程时阻塞状态;
//
//try {
//    sleep(1000);
//} catch (InterruptedException e) {
//    e.printStackTrace();
//}
//
//inAlive(): 判断当前线程是否存活，返回值类型为 boolean。
//
//System.out.println(t1.inAlive);
//
//五、线程的优先级
//线程中的优先级范围为1~10，其中较为特殊的三个优先级在 Java 的 Thread类 中已经内置好了，分别为 MAX_PRIORITY、MIN_PRIORITY 
//和 NORM_PRIORITY，分别代表优先级数值为10、1 和 5。在优先级中常用的两个方法如下：
//
//获取线程优先级：getPriority()
//设置线程优先级：setPriority()
//说明：高优先级的线程要抢占低优先级线程CPU的执行权。但是只是从概率上讲，高优先级的线程高概率的情况下被执行。并不意味着只有当高优先级的线程
//执行完以后，低优先级的线程才执行。
//
//public class ThreadPriority {
//    public static void main(String[] args) {
//        MyPriority p1 = new MyPriority();
//        p1.setPriority(Thread.MAX_PRIORITY);	///设置优先级为最高
//        p1.start();
//        for (int i = 0; i < 50; i++) {
//            if(i % 2 != 0) {
//                System.out.println(Thread.currentThread().getName() + ": " + Thread.currentThread().getPriority() + ": " + i);
//            }
//        }
//    }
//}
//
//class MyPriority extends Thread {
//    @Override
//    public void run() {
//        for (int i = 0; i < 50; i++) {
//            if(i % 2 == 0) {
//                System.out.println(Thread.currentThread().getName() + ": " + Thread.currentThread().getPriority() + ": " + i);
//            }
//        }
//    }
//}


